package com.rf.richfitwheel.admin.sys.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.rf.richfitwheel.admin.sys.dao.CodeDefMapper;
import com.rf.richfitwheel.admin.sys.dao.CodeRuleMapper;
import com.rf.richfitwheel.admin.sys.dao.CodeUseInfoMapper;
import com.rf.richfitwheel.admin.sys.dao.SqlAdapterMapper;
import com.rf.richfitwheel.admin.sys.model.CodeDef;
import com.rf.richfitwheel.admin.sys.model.CodeRule;
import com.rf.richfitwheel.admin.sys.model.CodeUseInfo;
import com.rf.richfitwheel.admin.sys.service.CodeUseInfoService;
import com.rf.richfitwheel.common.utils.PageUtils;
import com.rf.richfitwheel.common.utils.StringUtils;
import com.rf.richfitwheel.common.utils.UuidUtil;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Author bw Date 2019-05-05
 */
@Service
public class CodeUseInfoServiceImpl implements CodeUseInfoService {
	private static Logger log = LoggerFactory.getLogger(CodeUseInfoServiceImpl.class);
	/**
	 * 分布式锁的key,当遇到编码是流水号的时候需要用分布式锁来保证流水号不重复
	 */
	private static final String CODE_USE_LOCK_KEY = "codeRuleLockKey_";
	/**
	 * 锁过期时间10s
	 */
	private static final long CODE_USE_LOCK_EXPIRE = 10 * 1000L;
	
	/**
	 * 重试时间1000ms
	 */
	private static final long CODE_USE_TRY_INTERVAL = 1000L;
	/**
	 * 超时时间
	 */
	private static final long CODE_USE_TRY_TIMEOUT = 5 * 1000L;

	@Resource
	private CodeUseInfoMapper codeUseInfoDao;

	@Resource
	private CodeRuleMapper codeRuleDao;

	@Resource
	private CodeDefMapper codeDefDao;

	@Resource
	private SqlAdapterMapper sqlAdapterMapper;// 注入dao

	@Resource
	private RedisTemplate<String, String> redisTemplate;
	
	@Override
	public CodeUseInfo get(String id) {
		return codeUseInfoDao.get(id);
	}

	@Override
	public List<CodeUseInfo> findList(CodeUseInfo codeUseInfo) {
		return codeUseInfoDao.findList(codeUseInfo);
	}

	@Override
	public List<CodeUseInfo> findAllList() {
		return codeUseInfoDao.findAllList();
	}

	@Override
	public int insert(CodeUseInfo codeUseInfo) {
		return codeUseInfoDao.insert(codeUseInfo);
	}

	@Override
	public int insertBatch(List<CodeUseInfo> codeUseInfos) {
		return codeUseInfoDao.insertBatch(codeUseInfos);
	}

	@Override
	public int update(CodeUseInfo codeUseInfo) {
		return codeUseInfoDao.update(codeUseInfo);
	}

	@Override
	public int delete(CodeUseInfo codeUseInfo) {
		return codeUseInfoDao.delete(codeUseInfo);
	}
	
	//查询分页记录
	@Override
	public PageUtils queryPage(Map<String, Object> params) {
		try {

			String codeDefId = (String) params.get("id");
			String code = "";
			if(codeDefId!=null && !"".equals(codeDefId)) {
				CodeDef codeDef = codeDefDao.selectByPrimaryKey(codeDefId);//
				code=codeDef.getCode();
			}
			PageUtils pageUtils = PageUtils.getPageInfo(params);
			Page<Object> p = PageHelper.startPage(pageUtils.getPage(), pageUtils.getLimit());
			StringBuffer sql = new StringBuffer(
					" select cu.id,cu.code,cu.rules,cu.maxid,cu.maxidstr,cu.useflag,DATE_FORMAT(cu.usedate,'%Y-%m-%d %H:%i:%s') as usedate,cu.version from sys_code_use_info cu ");
			CodeUseInfo codeUseInfo = (CodeUseInfo) JSONObject.toBean(JSONObject.fromObject(params.get("dataForm")),
					CodeUseInfo.class);

			if(!"".equals(code)){
				sql.append(" where cu.code = '"+code+"'");
			}
			
			sql.append(" order by cu.rules, cu.maxid,cu.usedate");
			sqlAdapterMapper.selectSQL(sql.toString());
			pageUtils = new PageUtils(p);
			List<Map<String, String>> mapList = (List<Map<String, String>>) pageUtils.getList();
			
			pageUtils.setList(mapList);
			return pageUtils;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 获取一个编码
	 * @param param:规则类型为参数时的变量，若有多个逗号分隔
	 */
	@Override
    @Transactional(rollbackFor = Exception.class)
	public  String getOne(String code, String param) {
		String sUuid = "";
		try {
			List<CodeRule> codeRuleList = codeRuleDao.getCodeRuleList(code);
			String[] paramArray;
			if(StringUtils.isNotBlank(param)) {
				paramArray = param.split(",");
			}else {
				paramArray = new String[0];
			}
			
			// 如果不能查到，直接返回null
			if (codeRuleList == null) {
				return null;
			}

			// 如果参数数量和规则需要的参数数量不一样，返回null
			int paramTypeNum = 0;
			
			//算出参数类型的数量
			for (CodeRule codeRule : codeRuleList) {
				if ("4".contentEquals(codeRule.getKind())) {
					paramTypeNum += 1;
				}
			}
			if (paramArray.length != paramTypeNum) {
				return null;
			}
			//分布式锁标识
			boolean codeLock = false;
			//定义一个编码使用信息类，保存到数据库
			CodeUseInfo cui = new CodeUseInfo();
			//定义一个规则串
			StringBuffer ruleStr = new StringBuffer();
			//定义一个变量记录最大流水号
			Integer maxnum = 0;
			// 定义一个空字符串
			StringBuffer sb = new StringBuffer();
			//定义一个参数用来记录参数规则的位置
			int paramKindIndex = 0;
			int paramKindIndex2 = 0;
			// 剩下的就是规则表有对应的编码编号，且参数个数和需要的参数个数相同
			//生成规则串
			for (CodeRule codeRule : codeRuleList) {
				// 如果是常量
				if ("1".equals(codeRule.getKind())) {
					//如果是生成规则及因子
					if("1".equals(codeRule.getDivisor())) {
						ruleStr.append(codeRule.getRule());
					}
				}
				// 如果是关键字
				if ("2".equals(codeRule.getKind())) {
					String str=getKeyStr(codeRule.getRule());
					//如果是生成规则及因子
					if("1".equals(codeRule.getDivisor())) {
						ruleStr.append(str);
					}
				}
				//如果是参数
				if ("4".equals(codeRule.getKind())) {
					if(paramArray.length>0) {
						//如果是生成规则及因子
						if("1".equals(codeRule.getDivisor())) {
							ruleStr.append(paramArray[paramKindIndex2]);
						}
						paramKindIndex2++;
					}
				}

			}
			//生成编码串
			for (CodeRule codeRule : codeRuleList) {
				// 如果是常量
				if ("1".equals(codeRule.getKind())) {
					sb.append(codeRule.getRule());
				}
				// 如果是关键字
				if ("2".equals(codeRule.getKind())) {
					String str=getKeyStr(codeRule.getRule());
					sb.append(str);
				}
				
				//如果是流水号
				if ("3".equals(codeRule.getKind())) {
					sUuid = UuidUtil.get32UUID();
					//流水号的情况下需要分布式锁来避免重号
					codeLock = testRedisLock(codeRule.getCode(), sUuid);
					if(!codeLock){
						log.error("获取分布式锁失败");
						return "";
					}
					CodeUseInfo cUseInfo = new CodeUseInfo();
					cUseInfo.setCode(code);
					cUseInfo.setRules(ruleStr.toString());
					List<CodeUseInfo> codeUseInfoList = codeUseInfoDao.getListByCodeAndRules(cUseInfo);
					//获得流水号规则的最小值
					Integer snmin = codeRule.getSnmin();
					//获得流水号规则的最大值
					Integer snmax = codeRule.getSnmax();
					//获得流水号的长度
					Integer snsize = codeRule.getSnsize();
					//获得流水号规则是否定长
					String snfixlen = codeRule.getSnfixlen();
					String num="";
					//还没有记录
					if(codeUseInfoList==null||codeUseInfoList.size()==0) {
						if("1".equals(snfixlen)) {
							num = getNum(snmin, snsize);
						}else {
							num = snmin.toString();
						}
						if(!ObjectUtils.isEmpty(snmin)){
							maxnum = snmin;
						}else{
							maxnum = 1;
						}

						sb.append(num);
					}
					//如果已经有记录
					if(codeUseInfoList!=null&&codeUseInfoList.size()>0) {
						CodeUseInfo codeUseInfo = codeUseInfoList.get(codeUseInfoList.size()-1);
						//获得最后一个编号
						Integer maxid = codeUseInfo.getMaxid();
						//判断最后一个编号是否<最大编号
						if(maxid<snmax) {
							if("1".equals(snfixlen)) {
								num = getNum(maxid+1, snsize);
							}else {
								num = maxid+1+"";
							}
							
							sb.append(num);
							maxnum = maxid + 1;
							
						}else {
							//否则直接返回null
							return null;
						}
					}
				}
				//如果是参数
				if ("4".equals(codeRule.getKind())) {
					if(paramArray.length>0) {
						sb.append(paramArray[paramKindIndex]);
						paramKindIndex++;
					}
				}

			}
			//将cui保存到数据库
			cui.setId(UuidUtil.get32UUID());
			cui.setCode(code);
			cui.setMaxid(maxnum);
			cui.setMaxidstr(sb.toString());
			cui.setRules(ruleStr.toString());
			cui.setUsedate(new Date());
			cui.setUseflag("1");
			codeUseInfoDao.insert(cui);
			//如果有锁则释放
			if(codeLock && StringUtils.isNotBlank(sUuid)){
				releaseLock(code, sUuid);
			}
			return sb.toString();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}finally{
			releaseLock(code, sUuid);
		}
	}
	
	//批量生成编号
	@Override
    @Transactional(rollbackFor = Exception.class)
	public List<String> getBacth(String code, String param, int num) {
		String sUuid = "";
		
		List<String> listr = new ArrayList<String>();
		try {
			List<CodeRule> codeRuleList = codeRuleDao.getCodeRuleList(code);
			String[] paramArray = StringUtils.isNotBlank(param) ? param.split(",") : new String[0];
			// 如果不能查到，直接返回null
			if (codeRuleList == null) {
				return null;
			}
			// 如果参数数量和规则需要的参数数量不一样，返回null
			int paramTypeNum = 0;
			//算出参数类型的数量
			for (CodeRule codeRule : codeRuleList) {
				if ("4".contentEquals(codeRule.getKind())) {
					paramTypeNum += 1;
				}
			}
			if (paramArray.length != paramTypeNum) {
				return null;
			}
			
			//分布式锁标识
			boolean codeLock = false;
			sUuid = UuidUtil.get32UUID();
			//流水号的情况下需要分布式锁来避免重号
			codeLock = testRedisLock(code, sUuid);
			if(!codeLock){
				log.error("获取分布式锁失败");
				return null;
			}
			//规则串
			StringBuilder ruleStr = new StringBuilder();
			//定义一个参数用来记录参数规则的位置
			int paramKindIndex2 = 0;
			for(CodeRule codeRule : codeRuleList){
				switch(codeRule.getKind()){
					//常量
					case "1":{
						//如果是生成规则及因子
						if("1".equals(codeRule.getDivisor())){
							ruleStr.append(codeRule.getRule());
						}
						break;
					}
					//关键字
					case "2":{
						String str = getKeyStr(codeRule.getRule());
						//如果是生成规则及因子
						if("1".equals(codeRule.getDivisor())){
							ruleStr.append(str);
						}
						break;
					}
					//参数
					case "4":{
						if(paramArray.length > 0){
							//如果是生成规则及因子
							if("1".equals(codeRule.getDivisor())){
								ruleStr.append(paramArray[paramKindIndex2]);
							}
							paramKindIndex2++;
						}
						break;
					}
					default:
						break;
				}
			}
			CodeUseInfo cUseInfo = new CodeUseInfo();
			cUseInfo.setCode(code);
			cUseInfo.setRules(ruleStr.toString());
			List<CodeUseInfo> codeUseInfoList = codeUseInfoDao.getListByCodeAndRules(cUseInfo);
			//定义一个变量记录最大流水号
			int maxnum = 0;
			//循环取编码,取num个编码
			for(int x = 0; x < num; x++){
				//定义一个参数用来记录参数规则的位置
				int paramKindIndex = 0;
				//按顺序排的，所以从前到后拼接就行
				//编码串
				StringBuilder sb = new StringBuilder();
				
				for(CodeRule codeRule : codeRuleList){
					switch(codeRule.getKind()){
						//常量
						case "1":{
							sb.append(codeRule.getRule());
							break;
						}
						//关键字
						case "2":{
							String str = getKeyStr(codeRule.getRule());
							sb.append(str);
							break;
						}
						//流水号
						case "3":{
							//获得流水号规则的最小值
							Integer snmin = codeRule.getSnmin();
							//获得流水号规则的最大值
							Integer snmax = codeRule.getSnmax();
							//获得流水号的长度
							Integer snsize = codeRule.getSnsize();
							//获得流水号规则是否定长
							String snfixlen = codeRule.getSnfixlen();
							String numCode = "";
							if(x > 0){
								//第二个号开始直接取maxnum+1
								maxnum = maxnum + 1;
								if("1".equals(snfixlen)){
									numCode = getNum(maxnum, snsize);
								}else{
									numCode = Integer.toString(maxnum);
								}
								sb.append(numCode);
							}else{
								//还没有记录
								if(codeUseInfoList.isEmpty()){
									if("1".equals(snfixlen)){
										numCode = getNum(snmin, snsize);
									}else{
										numCode = snmin.toString();
									}
									if(!ObjectUtils.isEmpty(snmin)){
										maxnum = snmin;
									}else{
										maxnum = 1;
									}
									sb.append(numCode);
								}else{
									CodeUseInfo codeUseInfo = codeUseInfoList.get(0);
									//获得最后一个编号
									Integer maxid = codeUseInfo.getMaxid();
									//判断最后一个编号是否<最大编号
									if(maxid < snmax){
										if("1".equals(snfixlen)){
											numCode = getNum(maxid + 1, snsize);
										}else{
											numCode = maxid + 1 + "";
										}
										sb.append(numCode);
										maxnum = maxid + 1;
									}else{
										//否则直接返回null
										return null;
									}
								}
							}
							break;
						}
						//参数
						case "4":{
							if(paramArray.length > 0){
								sb.append(paramArray[paramKindIndex]);
								paramKindIndex++;
							}
							break;
						}
						default:
							break;
					}
				}
				listr.add(sb.toString());
				//将cui保存到数据库
				CodeUseInfo cui = new CodeUseInfo();
				cui.setId(UuidUtil.get32UUID());
				cui.setCode(code);
				cui.setMaxid(maxnum);
				cui.setMaxidstr(sb.toString());
				cui.setRules(ruleStr.toString());
				cui.setUsedate(new Date());
				cui.setUseflag("1");
				codeUseInfoDao.insert(cui);
			}
			
		}finally{
			releaseLock(code, sUuid);
		}
		
		return listr;
	}
	
	//回收单个编号
	@Override
    @Transactional(rollbackFor = Exception.class)
	public String setOne(String code, String codes) {
		try {
			//根据编码编号查找数据库是否有使用记录
			CodeUseInfo cui = new CodeUseInfo();
			cui.setCode(code);
			cui.setMaxidstr(codes);
			if(codes ==null || "".equals(codes)) {
				return null;
			}
			//根据编码编号和编号字符串查找使用记录
			CodeUseInfo codeUseInfo = codeUseInfoDao.getByCodeAndMaxidstr(cui);
			if(codeUseInfo == null) {
				return null;
			}else {
				codeUseInfo.setUseflag("2");
				codeUseInfoDao.update(codeUseInfo);
				return "回收成功";
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	// 批量回收编号
	@Override
    @Transactional(rollbackFor = Exception.class)
	public String setBatch(String code, String codes) {
		try {
			if(codes ==null || "".equals(codes)) {
				return null;
			}
			String[] codeStrArray = codes.split(",");
			for (String codeStr : codeStrArray) {
				String res = setOne(code, codeStr);
				if(res==null) {
					return null;
				}
			}
			return "回收成功";
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 批量获取老方法，内部调用单个的方法
	 *
	 * @param code     编码
	 * @param paramMe  参数
	 * @param parseInt 个数
	 * @return 结果
	 */
	@Override
	public List<String> getBacthFromOne(String code, String paramMe, int parseInt){
		List<String> list = new ArrayList<>();
		for (int i = 0; i < parseInt; i++) {
			String str = getOne(code, paramMe);
			if(str !=null&&!"".equals(str)) {
				list.add(str);
			}
		}
		return list;
	}
	
	
	// 根据日期关键字获得字符串
	public String getKeyStr(String key) {
		Date now=new Date();
		String str="";
	      
		if ("YYYY".equals(key)) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
			str = sdf.format(now);
			
		}
		if ("YY".equals(key)) {
			SimpleDateFormat sdf = new SimpleDateFormat("yy");
			str = sdf.format(now);
		}
		if ("MM".equals(key)) {
			SimpleDateFormat sdf = new SimpleDateFormat("MM");
			str = sdf.format(now);
		}
		if ("DD".equals(key)) {
			SimpleDateFormat sdf = new SimpleDateFormat("dd");
			str = sdf.format(now);
		}

		return str;
	}
	
	//生成指定长度的数字
	//生成指定长度的数字
	public String getNum(Integer num,Integer length) {
		String s = "";
		for(int i = 0;i<length;i++) {
			s+="0";
		}
		DecimalFormat f = new DecimalFormat(s);
		String str = f.format(num);
		return str;
	}

	/**
	 * 数据库没有使用，所以不增加流水号
	 */
	@Override
    @Transactional(rollbackFor = Exception.class)
	public Map<String,Object> getOneButNotAdd(String code, String param) {
		String sUuid = "";
		try {
			List<CodeRule> codeRuleList = codeRuleDao.getCodeRuleList(code);
			String[] paramArray;
			if(StringUtils.isNotBlank(param)) {
				paramArray = param.split(",");
			}else {
				paramArray = new String[0];
			}
			
			// 如果不能查到，直接返回null
			if (codeRuleList == null) {
				return null;
			}

			// 如果参数数量和规则需要的参数数量不一样，返回null
			int paramTypeNum = 0;
			
			//算出参数类型的数量
			for (CodeRule codeRule : codeRuleList) {
				if ("4".contentEquals(codeRule.getKind())) {
					paramTypeNum += 1;
				}
			}
			if (paramArray.length != paramTypeNum) {
				return null;
			}
			//分布式锁标识
			boolean codeLock = false;
			//定义一个编码使用信息类，保存到数据库
			CodeUseInfo cui = new CodeUseInfo();
			//定义一个规则串
			StringBuffer ruleStr = new StringBuffer();
			//定义一个变量记录最大流水号
			Integer maxnum = 0;
			// 定义一个空字符串
			StringBuffer sb = new StringBuffer();
			//定义一个参数用来记录参数规则的位置
			int paramKindIndex = 0;
			int paramKindIndex2 = 0;
			// 剩下的就是规则表有对应的编码编号，且参数个数和需要的参数个数相同
			//生成规则串
			for (CodeRule codeRule : codeRuleList) {
				// 如果是常量
				if ("1".equals(codeRule.getKind())) {
					//如果是生成规则及因子
					if("1".equals(codeRule.getDivisor())) {
						ruleStr.append(codeRule.getRule());
					}
				}
				// 如果是关键字
				if ("2".equals(codeRule.getKind())) {
					String str=getKeyStr(codeRule.getRule());
					//如果是生成规则及因子
					if("1".equals(codeRule.getDivisor())) {
						ruleStr.append(str);
					}
				}
				//如果是参数
				if ("4".equals(codeRule.getKind())) {
					if(paramArray.length>0) {
						//如果是生成规则及因子
						if("1".equals(codeRule.getDivisor())) {
							ruleStr.append(paramArray[paramKindIndex2]);
						}
						paramKindIndex2++;
					}
				}

			}
			//生成编码串
			for (CodeRule codeRule : codeRuleList) {
				// 如果是常量
				if ("1".equals(codeRule.getKind())) {
					sb.append(codeRule.getRule());
				}
				// 如果是关键字
				if ("2".equals(codeRule.getKind())) {
					String str=getKeyStr(codeRule.getRule());
					sb.append(str);
				}
				//如果是流水号
				if ("3".equals(codeRule.getKind())) {
					sUuid = UuidUtil.get32UUID();
					//流水号的情况下需要分布式锁来避免重号
					codeLock = testRedisLock(codeRule.getCode(), sUuid);
					if(!codeLock){
						log.error("获取分布式锁失败");
						Map<String,Object> mapX = new HashMap<String, Object>();
						mapX.put("str","");
						mapX.put("codeId","");
						return mapX;
					}
					CodeUseInfo cUseInfo = new CodeUseInfo();
					cUseInfo.setCode(code);
					cUseInfo.setRules(ruleStr.toString());
					List<CodeUseInfo> codeUseInfoList = codeUseInfoDao.getListByCodeAndRulesAndBeUsed(cUseInfo);
					//获得流水号规则的最小值
					Integer snmin = codeRule.getSnmin();
					//获得流水号规则的最大值
					Integer snmax = codeRule.getSnmax();
					//获得流水号的长度
					Integer snsize = codeRule.getSnsize();
					//获得流水号规则是否定长
					String snfixlen = codeRule.getSnfixlen();
					String num="";
					//还没有记录
					if(codeUseInfoList==null||codeUseInfoList.size()==0) {
						if("1".equals(snfixlen)) {
							num = getNum(snmin, snsize);
						}else {
							num = snmin.toString();
						}
						
						maxnum +=1;
						sb.append(num);
					}
					//如果已经有记录
					if(codeUseInfoList!=null&&codeUseInfoList.size()>0) {
						CodeUseInfo codeUseInfo = codeUseInfoList.get(codeUseInfoList.size()-1);
						//获得最后一个编号
						Integer maxid = codeUseInfo.getMaxid();
						//判断最后一个编号是否<最大编号
						if(maxid<snmax) {
							if("1".equals(snfixlen)) {
								num = getNum(maxid+1, snsize);
							}else {
								num = maxid+1+"";
							}
							
							sb.append(num);
							maxnum = maxid + 1;
							
						}else {
							//否则直接返回null
							return null;
						}
					}
				}
				//如果是参数
				if ("4".equals(codeRule.getKind())) {
					if(paramArray.length>0) {
						sb.append(paramArray[paramKindIndex]);
						paramKindIndex++;
					}
				}

			}
			//将cui保存到数据库
			String id = UuidUtil.get32UUID();
			cui.setId(id);
			cui.setCode(code);
			cui.setMaxid(maxnum);
			cui.setMaxidstr(sb.toString());
			cui.setRules(ruleStr.toString());
			cui.setUsedate(new Date());
			cui.setUseflag("2");
			codeUseInfoDao.insert(cui);
			//如果有锁则释放
			if(codeLock && StringUtils.isNotBlank(sUuid)){
				releaseLock(code, sUuid);
			}
			Map<String,Object> map = new HashMap<String, Object>();
			map.put("str",sb.toString());
			map.put("codeId",id);
			return map;
		} catch (Exception e) {
			e.printStackTrace();

			// TODO: WTF ?
			return null;
		}finally{
			releaseLock(code, sUuid);
		}
		
		
	}
	
	/**
	 * 获取分布式锁的方法，返回true表示正常获取锁，否则表示没获取到锁。
	 * @param key 锁key
	 * @param uuid 锁值
	 * @return 锁获取结果
	 */
	public boolean testRedisLock(String key, String uuid){
		Boolean lock = redisTemplate.opsForValue().setIfAbsent(CODE_USE_LOCK_KEY + key, uuid, CODE_USE_LOCK_EXPIRE, TimeUnit.MILLISECONDS);
		//如果获取到锁执行
		if(lock){
			return true;
		}else{
			//如果没有获取到锁，睡眠100秒后重试直到获取到锁，通过回调继续获取锁
			try {
				Thread.sleep(100);
				return testRedisLock(key, uuid);
			} catch (InterruptedException e) {
				log.error(e.getMessage(), e);
			}
		}
		return false;
	}
	public void releaseLock(String key, String uuid){
		//在极端情况下仍然会误删除锁
		//因此使用lua脚本的方式来防止误删除
		String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
				"then\n" +
				"    return redis.call(\"del\",KEYS[1])\n" +
				"else\n" +
				"    return 0\n" +
				"end";
		DefaultRedisScript defaultRedisScript = new DefaultRedisScript();
		defaultRedisScript.setScriptText(script);
		defaultRedisScript.setResultType(Long.class);
		redisTemplate.execute(defaultRedisScript, Arrays.asList(CODE_USE_LOCK_KEY + key), uuid);
	}

}
